## computerVision Big——Job
## 2024 - 11 -26
import sys

import numpy as np
import cv2 as cv

# 提取银行卡模块
def get_card(image):
    # 读入银行卡对银行卡进行处理如果是有白边，提取银行卡
    img = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    img = cv.medianBlur(img, 5)
    _,img_Bin= cv.threshold(img, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)
    # 反转二值图像
    binary = cv.bitwise_not(img_Bin)
    # 查找轮廓
    contours, _ = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    # 找到最大轮廓
    max_contour = max(contours, key=cv.contourArea)
    # 创建一个蒙版
    mask = np.zeros_like(image)
    # 填充最大轮廓
    cv.drawContours(mask, [max_contour], -1, (255, 255, 255), thickness=cv.FILLED)
    # 使用蒙版提取银行卡部分
    result = cv.bitwise_and(image, mask)
    # 获得图像的边界框
    x, y, w, h = cv.boundingRect(max_contour)
    cropped_card = result[y:y + h, x:x + w]
    # cv.imshow("cropped_image",cropped_card)
    return cropped_card

##提取数字模块
def number_select(image):

    # 截取卡号部分
    rows,cols = image.shape[:2]
    img0 = image[int(rows/2):int(0.7*rows),0:cols]
    cv.imshow("img0",img0)
    # 中值滤波，二值化
    img = cv.cvtColor(img0, cv.COLOR_BGR2GRAY)

    # # 对于图四，处理光亮不同的图像的情况，使用自适应的直方图均衡化处理图像
    # 图五注释该部分
    clahe = cv.createCLAHE(clipLimit=8.0,tileGridSize=(8,8))
    img = clahe.apply(img)

    # img = cv.medianBlur(img, 5) # 图五时，不使用中值滤波，如果使用中值滤波图五数字后面的印花会和数字重叠冲突

    _,img_Bin= cv.threshold(img, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)
    # # 膨胀连接数字
    # kernel1 = np.ones((1,17),np.uint8)
    # img_mor = cv.dilate(img_Bin,kernel1,)
    # # 闭运算，填充孔洞
    # kernel2 = np.ones((5,5),np.uint8)
    # img_close = cv.morphologyEx(img_mor,cv.MORPH_CLOSE,kernel2)
    # 边缘计算
    cv.imshow("img_bin",img_Bin)
    contours,hierarychy = cv.findContours(img_Bin,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
    n = len(contours)
    # 存储外接矩形的矩阵
    # 每个模板的左上角点参数（x,y,w,h）
    RectBoxes0 = np.ones((n,4),dtype=int)# n行 4列
    for i in range(n):
        RectBoxes0[i] = cv.boundingRect(contours[i])


    y_values = RectBoxes0[:, 1]
    # print("Rect",RectBoxes0)
    # print("y_values",y_values)
    unique_y, counts = np.unique(y_values, return_counts=True)
    y_with_four = unique_y[counts >= 12]
    result_rows = []
    for y_value in y_with_four:
        matching_rows = RectBoxes0[y_values == y_value]
        result_rows.extend(matching_rows.tolist())

    if result_rows:
        for row in result_rows:
            y_result = row[1]
            h_result = row[3]
            break;
    rows,cols = img.shape[:2]
    img_result = img0[(y_result):(y_result+h_result+5),0:cols]

    img = cv.cvtColor(img_result,cv.COLOR_BGR2GRAY)
    img = cv.resize(img,(int(3*img.shape[1]),int(3*img.shape[0])))
    _,binary_image = cv.threshold(img,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
    kernel = np.ones((3,3),np.uint8)
    num_image = cv.dilate(binary_image,kernel,iterations=1)

    return num_image

## 模板处理
def get_model(model_item):
    num_item = cv.cvtColor(model_item,cv.COLOR_BGR2GRAY)
    ret,num_item = cv.threshold(num_item,200,255,cv.THRESH_BINARY_INV)
    return num_item

# 数字模板框选
def sequence_contours(image,width,height):

    contours,hierarychy = cv.findContours(image,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
    n = len(contours)
    # 存储外接矩形的矩阵
    # 每个模板的左上角点参数（x,y,w,h）
    RectBoxes0 = np.ones((n,4),dtype=int)# n行 4列
    for i in range(n):
        RectBoxes0[i] = cv.boundingRect(contours[i])

    print("RectBoxes0",RectBoxes0)
    RectBoxes = np.ones((n,4),dtype=int)
    for i in range(n):
        sequence = 0
        for j in range(n):
            if RectBoxes0[i][0] > RectBoxes0[j][0]:
                sequence = sequence + 1
            RectBoxes[sequence] = RectBoxes0[i]

    image_box = [[] for i in range(n)]
    for i in range(n):
        x,y,w,h = RectBoxes[i]
        ROI = image[y:y+h,x:x+w]
        ROI = cv.resize(ROI,(width,height))
        thresh_val,ROI = cv.threshold(ROI,200,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
        image_box[i] = ROI
    return RectBoxes,image_box


# 读入待匹配图片
img = cv.imread("images/credit_card_01.png.png")
# 读入模板图片
item_img = cv.imread("images/model_item.png")
# 预处理模板图片
image_item = get_model(item_img)
# 预处理待匹配图片
image_card = get_card(img)
cv.imshow("image_card",image_card)
image_num = number_select(image_card)

# 模板数字截取
rectbox_item,imagebox_item = sequence_contours(image_item,60,90)
# 匹配图像数字截取
rectbox,imagebox = sequence_contours(image_num,60,90)

result = []
for i in range(len(imagebox)):
    score = np.zeros(len(imagebox_item),dtype=int)
    for j in range(len(imagebox_item)):
        score[j] = cv.matchTemplate(imagebox_item[j],imagebox[i],cv.TM_SQDIFF)
        minValue, maxValue, minLoc, maxLoc = cv.minMaxLoc(score)
    result.append(minLoc[1])

print(result)

cv.imshow("yuantu",img)
# cv.imshow("item",image_item)
cv.waitKey()
cv.destroyAllWindows()